﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FCS
{
    #region Map<T, U>

    sealed class Map<T, U> : FunList<U>
    {
        private IFunList<T> List { get; set; }
        private FunUnary<T, U> Action { get; set; }
        private FunUnaryIdx<T, U> ActionIdx { get; set; }
        private Cache<T, U> _mapCache = new Cache<T, U>();
        private bool _useCache = false;

        public Map(FunUnary<T, U> action, IFunList<T> list)
        {
            List = list;
            Action = action;
        }

        public Map(FunUnaryIdx<T, U> actionIdx, IFunList<T> list)
        {
            List = list;
            ActionIdx = actionIdx;
        }

        #region IEnumerable<U> Members

        public override IEnumerator<U> GetEnumerator()
        {
            if (!_useCache)
            {
                if (Action != null)
                {
                    foreach (T val in List)
                    {
                        yield return Action(val);
                    }
                }
                else
                {
                    int idx = 0;
                    foreach (T val in List)
                    {
                        yield return ActionIdx(val, idx);
                        idx++;
                    }
                }
            }
            else
            {
                if (Action != null)
                {
                    int idx = 0;
                    foreach (T val in List)
                    {
                        yield return _mapCache.CacheItem(Action, val, idx);
                        idx++;
                    }
                }
                else
                {
                    int idx = 0;
                    foreach (T val in List)
                    {
                        yield return _mapCache.CacheItem(ActionIdx, val, idx);
                        idx++;
                    }
                }
            }
        }

        #endregion
    }

    #endregion

    #region MapV2L<T, U>

    sealed class MapV2L<T, U> : FunList<IFunList<U>>
    {
        private IFunList<T> List { get; set; }
        private FunUnaryL<T, U> Action { get; set; }

        public MapV2L(FunUnaryL<T, U> action, IFunList<T> list)
        {
            List = list;
            Action = action;
        }

        #region IEnumerable<T, U> Members

        public override IEnumerator<IFunList<U>> GetEnumerator()
        {
            foreach (T val in List)
            {
                yield return Action(val);
            }
        }

        #endregion
    }

    #endregion

    #region MapL2L<T>

    sealed class MapL2L<T, U> : FunList<IFunList<U>>
    {
        private IFunList<IFunList<T>> List { get; set; }
        private FunUnaryL<IFunList<T>, IFunList<U>> Action { get; set; }

        public MapL2L(FunUnaryL<IFunList<T>, IFunList<U>> action, IFunList<IFunList<T>> list)
        {
            List = list;
            Action = action;
        }

        #region IEnumerable<IFunList<T>, IFunList<U>> Members

        public override IEnumerator<IFunList<U>> GetEnumerator()
        {
            foreach (IFunList<T> l in List)
            {
                foreach(IFunList<U> val in Action(l))
                {
                    yield return val;
                }
            }
        }

        #endregion
    }

    #endregion
}
